/**
 * 音频播放
 * @author xiaoyi
 */
export default class AudiosManager {

    protected static _audioIDs: object = Object.create(null);
    protected static _audioClips: object = Object.create(null);
    /**这里面的音频会保证同时只有一段进行播放 */
    protected static keepSingletonClips: string[] = [];
    /**当前是否可以播放音乐 */
    private static _isStop: boolean = false;

    private static loadAudioAsset(audiosPath: string, isOnline: boolean = false, onProgress?: Function): Promise<cc.AudioClip> {
        return new Promise<cc.AudioClip>((resolve, reject) => {
            if (isOnline) {
                cc.assetManager.loadRemote(audiosPath, this.onProgress.bind(this, onProgress), (error: Error, assets: cc.Asset) => {
                    if (error) {
                        reject(error);
                    } else {
                        if (assets instanceof cc.AudioClip) {
                            resolve(assets)
                        }
                    }
                });
            } else {
                cc.assetManager.resources.load(audiosPath, this.onProgress.bind(this, onProgress), (error: Error, assets: cc.Asset) => {
                    if (error) {
                        cc.warn(error);
                        reject(error);
                    } else {
                        if (assets instanceof cc.AudioClip) {
                            resolve(assets)
                        }
                    }
                });
            }
        })
    }

    public static keepSingletonClipAdd(audiosPath: string) {
        if (this.keepSingletonClips.includes(audiosPath)) {
            return
        }
        this.keepSingletonClips.push(audiosPath);
    }

    public static delKeepSingletonClip(audiosPath: string) {
        this.keepSingletonClips = this.keepSingletonClips.filter(item => item !== audiosPath);
    }

    /**
     * 播放音乐
     * @param audiosPath 音频路径
     * @param loop 播放次数0为循环播放
     * @param volume 音量
     * @param isOnline 是否为线上环境
     * @param playbeginCb 刚开始播放音乐的回调
     * @param playEndCb 播放完成后的回调
     * @param onProgress 加载的进度中做些什么
     * @returns 
     */
    public static play(audiosPath: string, loop: number = 1, volume: number = 1, isOnline: boolean = false, playbeginCb?: Function, playEndCb?: Function, onProgress?: Function) {
        if (this._isStop) return;
        let clip = this._audioClips[audiosPath];
        if (!clip) {
            this.loadAudioAsset(audiosPath, isOnline, onProgress).then((clip: cc.AudioClip) => {
                this.onPlay(audiosPath, clip, loop, volume, playbeginCb, playEndCb);
            }).catch((error) => {
                cc.warn(error);
            });
        } else {
            this.onPlay(audiosPath, clip, loop, volume, playbeginCb, playEndCb);
        }
    }

    private static onPlay(audiosPath: string, clip: cc.AudioClip, loop: number = 1, volume: number = 1, playbeginCb?: Function, playEndCb?: Function, isFinishCallback: boolean = false): void {
        if (this.keepSingletonClips.includes(audiosPath)) {
            this.keepSingletonClips.forEach(item => this.stop(item))
        } else {
            if (!isFinishCallback) {
                this.stop(audiosPath);
            }
        }
        let audioID = cc.audioEngine.play(clip, loop === 0 ? true : false, volume);
        playbeginCb && playbeginCb();
        cc.audioEngine.setFinishCallback(audioID, () => {
            loop--;
            playEndCb && playEndCb();
            if (loop > 0) {
                this.onPlay(audiosPath, clip, loop, volume, null, null, true);
            }
        })
        this._audioIDs[audiosPath] = audioID;
        this._audioClips[audiosPath] = this._audioClips[audiosPath] ?? clip;
    }

    public static set isStop(value: boolean) {
        this._isStop = value;
    }

    public static get isStop() {
        return this._isStop
    }

    /**
     * 预加载音频
     * @param audiosPath 音频所处的位置 
     * @param isOnline 是否为线上环境
     * @returns 
     */
    public static preLoadAudio(audiosPath: string, isOnline: boolean = false) {
        if (this._audioClips[audiosPath]) {
            return;
        }
        if (isOnline) {
            cc.assetManager.loadRemote(audiosPath, null, (error: Error, assets: cc.Asset) => {
                if (error) {
                    cc.warn(error);
                } else {
                    if (assets instanceof cc.AudioClip) {
                        this._audioClips[audiosPath] = assets;
                    }
                }
            });
        } else {
            cc.assetManager.resources.preload(audiosPath, cc.AudioClip);
        }
    }

    public static stop(audiosPath: string): void {
        let audioID = this._audioIDs[audiosPath];
        if (audioID !== undefined) {
            cc.audioEngine.stop(audioID);
        }
    }

    /**音乐是否播放中 */
    public static isPlaying(clipName: string): boolean {
        let audioID = this._audioIDs[clipName];
        if (audioID) {
            let state = cc.audioEngine.getState(audioID);
            if (state == cc.audioEngine.AudioState.PLAYING) {
                return true;
            }
        }
        return false;
    }

    public static stopAll(): void {
        cc.audioEngine.stopAll();
    }

    protected static onProgress(onProgress?: Function): void {
        onProgress && onProgress()
    }
}
